package com.nageoffer.jobtrain.projects.service.handler.remind;

import com.alibaba.fastjson2.JSON;
import com.nageoffer.jobtrain.projects.common.enums.ContestRemindTypeEnums;
import com.nageoffer.jobtrain.projects.service.ContestService;
import com.nageoffer.jobtrain.projects.service.handler.remind.dto.ContestRemindDTO;
import com.nageoffer.jobtrain.projects.service.handler.remind.impl.SendAppMessageRemindContestTemplate;
import com.nageoffer.jobtrain.projects.service.handler.remind.impl.SendSmsRemindContestTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池执行相关的竞赛通知逻辑
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ContestRemindExecutor {
    private final ContestService contestService;
    private final SendAppMessageRemindContestTemplate sendAppMessageRemindContestTemplate;
    private final SendSmsRemindContestTemplate sendSmsRemindContestTemplate;

    /**
     * 执行具体提醒用户类型自定义线程池 - IO密集型处理
     * Runtime.getRuntime().availableProcessors() << 1,  - CPU核数 * 2
     * Runtime.getRuntime().availableProcessors() << 2,  - CPU核数 * 4
     * 60,                                               - 临时线程数存储的最大时间
     * TimeUnit.SECONDS,                                 - 时间单位
     * new SynchronousQueue<>(),                         - 不缓存任务
     * new ThreadPoolExecutor.CallerRunsPolicy()         - 不能丢弃拒绝提醒任务，使用提交该任务的线程来执行
     */
    private final ExecutorService executorService = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors() << 1,
            Runtime.getRuntime().availableProcessors() << 2,
            60,
            TimeUnit.SECONDS,
            new SynchronousQueue<>(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    /**
     * 执行预约提醒流程
     *
     * @param contestRemindDTO 通知请求入参
     */
    public void executeRemindCouponTemplate(ContestRemindDTO contestRemindDTO) {
        // 判断用户是否已经取消该优惠劵该预约时间点，如果已经取消就不进行将通知进行发送给用户
        if (contestService.isCancelRemind(contestRemindDTO)) {
            log.info("用户取消竞赛该时间点预约提醒，参数：{}", JSON.toJSONString(contestRemindDTO));
            return;
        }

        executorService.execute(() -> {
            switch (Objects.requireNonNull(ContestRemindTypeEnums.getByType(contestRemindDTO.getType()))) {
                case APP -> sendAppMessageRemindContestTemplate.remind(contestRemindDTO);
                case SMS -> sendSmsRemindContestTemplate.remind(contestRemindDTO);
                default -> {
                    // 这里为后面其他通知类型做一个扩展
                }
            }
        });
    }
}